package com.fanqj.resilience4j.controller;

import com.fanqj.resilience4j.service.ITestService;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.vavr.CheckedFunction0;
import io.vavr.CheckedFunction1;
import io.vavr.control.Try;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;

/**
 * 直接使用断路器
 * @author <a href="mailto:fanqijin@wxchina.com">fanqj</a>
 * @Date 2021年01月15日 10:57
 * @Version 6.4.1
 */
@RestController
public class CircuitBreakerController {

    private static final Logger logger = LoggerFactory.getLogger(CircuitBreakerController.class);

    @Autowired
    private ITestService iTestService;

    @GetMapping("/test")
    public String testCircuitBreaker() {
        CheckedFunction0<String> supplier = CircuitBreaker.decorateCheckedSupplier(circuitBreaker, () -> "Do return by CircuitBreaker!");
        Try<String> result = Try.of(supplier).map(value -> value + "success!");
        return result.getOrElse("CircuitBreaker fail!");

    }

    @GetMapping("/test1")
    public String testManyCircuitBreaker() {
        CheckedFunction0<String> supplier = CircuitBreaker.decorateCheckedSupplier(circuitBreaker, () -> "Do return by CircuitBreaker!");

        CircuitBreaker anotherCircuitBreaker = CircuitBreaker.ofDefaults("anotherTest");
        CheckedFunction1<String, String> anotherSupplier = CircuitBreaker.decorateCheckedFunction(anotherCircuitBreaker, (input) -> input + "success!");

        Try<String> result = Try.of(supplier).mapTry(anotherSupplier::apply);
        return result.getOrElse("CircuitBreaker fail!");
    }

   private static final CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("test2");

    @GetMapping("/test2")
    public String testCircuitBreakerMethod() {
        Supplier<String> decoratedSupplier = CircuitBreaker
                .decorateSupplier(circuitBreaker, () -> iTestService.test("CircuitBreaker"));
        String result = Try.ofSupplier(decoratedSupplier)
                .recover(throwable -> "Hello from Recovery")
                .map(value -> value + "! CircuitBreaker state: " + circuitBreaker.getState())
                .get();
        return result;
    }

    @GetMapping("/test4")
    public String testCircuitBreakerMethodSimple() {
        return circuitBreaker.executeSupplier(() -> iTestService.test("CircuitBreaker"));
    }

    @PostConstruct
    public void init() {
        CircuitBreakerConfig config = CircuitBreakerConfig.custom()
                //失败率阈值。当失败率等于或大于阈值时，断路器状态并关闭变为开启
                .failureRateThreshold(10)
                //慢调用率阈值，当慢调用比例大于等于阈值时，断路器开启
                .slowCallRateThreshold(100)
                //调用时间的阈值，高于该阈值的呼叫视为慢调用
                .slowCallDurationThreshold(Duration.ofSeconds(2))
                //断路器从开启过渡到半开应等待的时间
                .waitDurationInOpenState(Duration.ofMillis(1000))
                //断路器在半开状态下允许通过的调用次数
                .permittedNumberOfCallsInHalfOpenState(3)
                //断路器计算失败率或慢调用率之前所需的最小调用数（每个滑动窗口周期）
                .minimumNumberOfCalls(10)
                //配置滑动窗口的类型COUNT_BASED,TIME_BASED
                .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.TIME_BASED)
                //滑动窗口的大小
                .slidingWindowSize(5)
               // .recordException(e -> INTERNAL_SERVER_ERROR.equals(getResponse().getStatus()))
                //记录为失败并因此增加失败率的异常列表
                .recordExceptions(IOException.class, TimeoutException.class)
                //忽略的异常
             //   .ignoreExceptions(BusinessException.class, OtherBusinessException.class)
                .build();
        //创建circuitBreakerRegistry并把config设置为默认的配置
        CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(config);
        //使用默认配置创建断路器
        CircuitBreaker circuitBreaker1 = circuitBreakerRegistry.circuitBreaker("test1");

        CircuitBreaker circuitBreaker2 = circuitBreakerRegistry.circuitBreaker("test2",config);
        //直接创建CircuitBreaker
        CircuitBreaker circuitBreaker3 = CircuitBreaker.of("test3", config);
        //注册器添加事件处理
        circuitBreakerRegistry.getEventPublisher()
                .onEntryAdded(addEvent -> {})
                .onEntryRemoved(event -> {})
                .onEntryReplaced(event -> {});
        //断路器添加事件处理
        circuitBreaker1.getEventPublisher()
                .onSuccess(event -> logger.info(""))
                .onError(event -> logger.info(""))
                .onIgnoredError(event -> logger.info(""))
                .onReset(event -> logger.info(""))
                .onStateTransition(event -> logger.info(""));
        // 如果你想对所有事件的进行监听并处理，可以这样做
        circuitBreaker1.getEventPublisher()
                .onEvent(event -> logger.info(""));


    }
}
